#!/usr/bin/env python
#
# Copyright 2008 Richard J. Bell. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

""" Main application file for great-loop site.

great-loop.py implements a Google app engine geo wiki web site.  It was 
originally developed to support a comunity of users interested in 
America's Great Loop.  It is a personal project supporting my 
interest in doing the Great Loop and to experiment with several Google 
technologies including: todo

From a technology perspective it implements a geo wiki.  That is a set of 
wiki pages each of which may have a geographic location or path.

The site provides:
    - A wiki to hold reference information about the Great Loop or other 
      subject
    - Wiki entries may have geo locations, paths, etc
    - Entries with geo locations can be displayed on a google map
    - All entries are viewable in a list format
    - Wiki entries have comments
    - Anyone can view the entire site
    - Users can register
    - Registered users can add and edit wiki pages
    - Provisions for displaying NOAA raster and enc charts as a google map 
      mashup
"""

__version__ = '$Revision 0.1$'
__author__  = "Richard Bell <rbell01824@earthlink.net>"
__date__ = 'Dec 12, 2008'
__credits__ = """
Various portions of this code and site are derived from open sources
including:
            The geodatastore example, see http://code.google.com/p/geodatastore/ and
            http://code.google.com/p/geodatastore/
            The Google app engine code lab, 
            see http://code.google.com/p/google-app-engine-codelab/
            todo: add others that are used.
"""
#===========================================================================
"""
MODS:
20081212 - Start initial development
20090110 Added basePanel from earlier experients.  Integrated into site on 
         .../test.
20090110 1130 Checking
20090110 1130 Uploaded to google

20090110 put about page back in so there is always a page
20090110 put banner in basePanel.html
         added test icon
         replaced buttons on basePanel.html with icons
         changed hide panel to hide all but menu panel
         1616 upload to google
         1616 checkin 

20090110 fix logout & help - Need the following pages: SiteFAQ, SiteHome, StartPage, SiteHelp
         fix reference to start page to site home
         1709 checkin

20090111 fixed wikiedit to work properly in the old framework
         fixed wikimap to work with base.html
         deleted baselayout.html since it is no longer needed
         1312 upload
         1312 checkin

20090111 found and fixed bug in old map pages caused by new onload logic in base.html
         found and fixed bug in wiki edit using tinymce
         Note: there is a bug in the JS for the old map functions.  Don't bother fixing since I'll need to redo these for the new UI.
         1446 checkin
         1446 upload

20090111 added map to basePanel display
         1619 checkin of basePanel map logic that seems to work prior to some restructuring

20090111 rewrote resize logic to be a normative part of panel processing
         added map controls to map panel
         1700 checkin
         1700 upload

20090112 modify basePanel to display only a single wiki panel
         modified basePanel map to display PHYSICAL map 
         put in basic code for YG.WikiView to access the server to get content
         put in a dumy wikiget function to return a json object
         1038 checkin

20090112 got basic async request going
         made log and panels toggles
         1712 checkin
         1712 upload

20090112 modified GetPage to actually return text/plain and the wikified content
         modified map page to have a terrain map as the default
         fixed bug so that all panels are now overflow auto
         1809 checkin
         1809 upload

20090113 adjusted CSS to deal with smaller screens
         1617 checkin & upload

20090113 added top right handles to basePanel panels
         set handle background color to blue to make them more prominent
         note: tried using a fixed relative path but firefox will not reliably
         render an image
         found and fixed bug on wikiedit so title is properly shown
         moved copyright into header to provide more vertical page flexability
         got basic map markers going
         1938 checkin & upload

20090114 # It's clear that a Web1+ implementation is both possible and useful for 
           development. So some cleanup work on base.html is in order.
         * Add onload and onunload handlers.
         * Change browser_title to BaseBrowserTitle so all the block names have the 
           same format. Ditto baseHead to BaseHead, BasePageMenu, BasePageTitleRight 
           (aka page_title_extra), BaseBody,
         * Removed mapPanel and changed code to use BaseBody
         * Henceforth Django template blocks are camel case, start with upper case, 
           no _         
         1059 checkin

20090114 
    # Added unload GUnload to wikiedit to remove browser memory leak
    # Henceforth id's are camel case, start with lower case, no _
        * fixed id's in basePanel.html
        * fixed id's in base.html
    # Removed text from menu to reduce width and tightened spacing
    # Removed basePanel.html at root since no longer need
    # checkin 1350

20090114
    * Added tooltips to menu icons on base.html and set background color
    * Added logreader to base.html
    * Created gwcommon.js to hold common js stuff
    * Put in logic to make body 100% height (still need to deal with browser sizing)
    * Revised onload/onunload logic so that page specific onload/onunload now 
      define their own functions that are called by the base onload/onunload 
      functions.  Washed changes through all effected code.
    * Put in logic to show/hide log reader.
    * checkin and upload 1800
    
20090114
    * created Rev2 (rev1 remains current)
    * checkin and upload 1816

20090115
    * Put in skip-files in app.yaml to skip Thumbs.db since they are not wanted. 
      The pattern was a bit surprising and took me some time to work out but 
      this is what worked (((.*)/)*Thumbs.db)|. I'm not sure why .*Thumbs.db or 
      simply Thumbs.db didn't work but they didn't.
While sorthing through some app engine group emails I found this CMS site. It 
might provide some interesting code examples. Pitty I didn't find it earlier as 
it might have provided a real leg up on development.
    * Started cleanup of tinyMCE.  Somewhere along the way IE quit working then 
      FF.  Need to finish getting things back to working tomorrow.

20090116
    # After a painful bit of incremental configuration work, it appears that the 
      issue with TinyMCE was using the filemanager and imagemanager plugins. These are 
      commercial products and IE died when trying to use them. Removed them from the 
      config and all appears well.
    # cleanup TinyMCE menu layout to deal with width issues
    # checkin and upload 0943

20090116
    * After a bit of fooling with the code and continuing issues with UI real 
      estate it became apparent that resizable draggable panels were wanted. 
      Implemented the panel code as a class.
          o defined basic PanelSet class
          o defined basic Panel
          o PanelSet code must execute prior to tinyMCE init (don't know why 
            but tinyMCE errors if it doesn't go last)
          o Experimented with yuiloader to simplfy loading of YUI css and js 
            files.  yuiloader is async!  As a consequence using it requires that
            any yuiloader dependent functions be fired from the success 
            attribute.  Said and done, it's not worth the effort.
          o removed class from PanelSet (again).  At the end of the day this is
            NOT appropriate for a class.
          o created icon to show/hide map panel
          o got map panel working.  There is an issue with putting both the map
            and controls in the same panel body.  The default resize logic 
            resizes the outter div and not the div containing the map.  As a 
            consequence checkResize doesn't work.  One fix is to modify the 
            resize logic to resize the inner content.  For now, I moved the 
            extra content to the panel hd.  It actually looks OK there so it's 
            good enough for now.
          o reenabled resizing on tinyMCE since the map is now in its own panel
          o sorted through some basic template issues
    * 1815 checkin and upload (version 3) 
    
20090118
Found and fixed bug preventing old


todo: add map to wikiview and list
todo: put in correct geolocation code on wikiedit
todo: connect geolocation on wikiedit
todo: put geo display on wikiview and list
todo: how to switch between simple and advanced editors
    

    todo: tooltip on map icon
    todo: tinymce use JS to toggle tinymce editor on/off, see ex 1 http://tinymce.moxiecode.com/examples/example_01.php
    todo: tinymce use readonly mode on tinymce, see ex7
    todo: tinymce load tinymce on demand, see ex 12
    todo: tinymce templates
    todo: tinymce when resize browser need to resize page components.  Looks like panels are a good solution.
    todo: setup handlers for login: required adn login:admin see http://code.google.com/appengine/docs/configuringanapp.html#Requiring_Login_or_Administrator_Status
    todo: add proper script interface for maps, see ????? or http://gmaps-samples.googlecode.com/svn-history/r2122/trunk/poly/mymapstoolbar.html
    todo: add proper unload handler to wikiedit and undo onload since it can be in header OK
    todo: rationalize names of wikiedit javascript functions
    todo: add privacy policy
    todo: implement wiki view in panel interface
    todo: implement wiki list in panel interface
    todo: make a class for our panels
    todo: add panel list to main menu
    todo: make logon, view, log, etc toggles
    todo: finish confirm
    todo: deal with
        #menu_panel_c.hide-scrollbars .yui-resize .bd { overflow: hidden; }
        #menu_panel_c.show-scrollbars .yui-resize .bd { overflow: auto; }
        #menu_panel_c.show-scrollbars .underlay { overflow: visible; }
    todo: add collapse to panel
    todo: add hide to panel
    todo: facility to list panels
    todo: document functions in std javascript way
    todo: replace px with em wherever to make browser scaling work properly
    todo: fix up dynamic panel panel widgets, positioning and graphics

todo:
    - logger colapse logic.  logger panel has a header, body, and footer
        collapse simply hides the body and footer
            collapse : function() {
                this._elConsole.style.display = "none";
                if(this._elFt) {
                    this._elFt.style.display = "none";
                }
                this._btnCollapse.value = "Expand";
                this.isCollapsed = true;
            },
enh: tinymce define templates for each type of page

"""

"""
Active work
Move user utilities from userhandlers.py to users.py
Add marker type to wiki (defines the kind of geo label to display)
todo: Add way to create wiki geo from wikiedit
todo: Add protected page flag
todo: fix focus issue in basePanel.html on home icon.  it displays with a dotted border on initial load
"""
"""
wiki
todo: Add map display for wiki view for any wiki with geo
todo: Add facility to select by label or search by title/description
todo: add about from http://www.bigbikemap.com/about info to SiteHome
todo: need a way to manage wiki comments
todo: add comments to wiki
enh: support wiki tags.  They are in the models but UI support is needed.
     should show on list, provide way for list by tags
     will also need similar support in maping features
enh: we need a way to manage how many wiki revisions
enh: add search near to wiki
enh: provide a query/search facility for wiki's based on 
      title/description
enh: Wikify should catch www.whatever.whatever... links
enh: add spell check to tinyMCE
enh: add a forum to the site.  See Fofou at http://forums.fofou.org
enh: show geolocation of wiki on view and edit pages in an adjustable 
     width window.  This can make map funcitons an integrap part of 
     the wiki UI!
enh: will need to do a paged handler for wiki list
enh: wiki admin interface to delete old wiki's and revert new wiki's
enh: arange for tinymcd and my CSS styles to be the same
enh: page ranking with flag for page removal.  generally need a way to
     manage pages in response to user input
enh: add mouse over feature to wiki list to show geo location of a wiki 
     if it has one
eng: add support for wiki markup as in 
     http://en.wikipedia.org/wiki/Wikipedia:Cheatsheet
     in particular add support for [[Name of page]] and
     [[Name of page|Text tod display]] wiki links.  See as well
     http://code.google.com/p/wikimarkup/ a google project that seems
     to support wiki markup processing in python and should be trivial
     to use
"""
"""
tags
todo: create a tags facility.  Tags need to have a model that supports 
      showing available tags on wiki page edit.  The tage should have a
      short name and a description.  I'll need facilities for managing
      extant tags and their use in wiki pages.  Aslo see
      http://en.wikipedia.org/wiki/How_to_edit
"""
"""
maps
todo: add a google geo search to site
todo: add a map route feature to site
todo: deal with geodatastore-vbr.kml, geohash.py, georssfeed.xml, 
      geoserv.py, and locator.py these are all geo related files that 
      should be moved to the app subdir
enh: refactor map features to drive everything off of the map display 
      page
"""
"""
user
todo: add userlist
todo: will need to do a paged handler for user list
enh: allow user to delete self
enh: black user list
enh: user admin interface
"""
"""
misc
fixme: on panel resize, top the resized panel
fixme: ERROR    2008-12-31 15:53:39,828 dev_appserver.py] Error encountered reading file "C:\Documents and Settings\Owner\Desktop\googleappserver\gl2\static\js/tiny_mce/plugins/imagemanag
er/editor_plugin.js":
[Errno 2] No such file or directory: 'C:\\Documents and Settings\\Owner\\Desktop\\googleappserver\\gl2\\static\\js/tiny_mce/plugins/imagemanager/editor_plugin.js'
INFO     2008-12-31 15:53:39,842 dev_appserver.py] "GET /static/js/tiny_mce/plugins/imagemanager/editor_plugin.js HTTP/1.1" 404 -
ERROR    2008-12-31 15:53:39,890 dev_appserver.py] Error encountered reading file "C:\Documents and Settings\Owner\Desktop\googleappserver\gl2\static\js/tiny_mce/plugins/filemanage
r/editor_plugin.js":
[Errno 2] No such file or directory: 'C:\\Documents and Settings\\Owner\\Desktop\\googleappserver\\gl2\\static\\js/tiny_mce/plugins/filemanager/editor_plugin.js'
todo: create privacy policy page off of home page.  generally follow google's policy
todo: use YUI in menus.  Add menu tooltips.
todo: review base.css and deleted unneeded styles
enh: add youtube feature to wiki to allow wiki to have associated list 
      of youtube videos
todo: move common.js into geo pages since it is only used there
todo: look into missing editor plugins
"""
#
#===========================================================================
# Work in progress code start
#===========================================================================
#def Y_NavigateWait( self, url,
#                    timeout = None,
#                    ...
#                    errorFlag = True, message = None ):
#    """ Navigate to a URL.  Wait for top document
#        complete then for no events.  Y_GoSearch is a navigation
#        and the usual Yamie navigation behaviors occur.
#    
#    Parameters:
#        timeout: opt, float, Seconds to wait before timeout.  
#                 Default self.timeout.
#        ...
#        flags, postData, headers, errorFlag, message: see Y_Navigate
#    
#    Returns: True on success.
#        None on COM error.
#        False on timeout.
#        Sets status and comError.
#    
#    Usage:
#    >>> yie.Y_NavigateWait('www.google.com', 30, 6)
#    True
#    
#    Note: As a practical matter only the url and flags are normally used.
#    """
#===========================================================================
# Work in progress code end
#===========================================================================

# Python Imports
import wsgiref.handlers

# Google App Engine Imports
from google.appengine.ext import webapp

# Application Imports
from app.baserequesthandler import BaseRequestHandler
from app import pagehandlers
from app import userhandlers
from app import maphandlers
from app import geohandlers
from geoserv import Request                     # todo: delete when have own geo facility
from geoserv import Geometry

# Set the debug level
_DEBUG = True

_ADMIN_EMAIL='rbell01824@earthlink.net'

class MainHandler(BaseRequestHandler):
    """ MainHandler extends the base request handler, and handles all
      requests to the urls not otherwise handled
  """
    def get(self):
        # todo: replace with wikiview of the startpage when things are working correctly
        self.generate('about.html', 
                      template_values={}) 

class TestHandler( BaseRequestHandler):
    """ Handles development test """
    def get(self):
        self.generate('basePanel.html', template_values={})

class RedirectHandler(BaseRequestHandler):
    """ RedirectHandler extends the base request handler, and handles all
      redirects
  """
    def get(self):
        #print '============'
        #print "request object cruft<<%s>>"%(self.request.path)
        #print '============'
        self.redirect( '/wikiview/' + self.request.path )

#
# URL plan
# /about - wikiview/about   Display the about page
# /mapedit - Display the map editor page 
# /mapview - View the map display page
# /mapkml - Display the map KML output page
# /wikilist - List wiki pages
# /wikiview/* - View wiki page
# /wikiedit/* - Edit wiki page
# /wikisave/* - Save edited wiki page
# /userlist - List users
# /userinfo/* - List info about user
# /useredit/* - Edit user
# /usergetphoto/* - Get user's photo
# /gen/request/* - Geo facilities
# /sendadminmail
#

_URLS = [('/about', MainHandler),
         ('/wikilist', pagehandlers.List),
         ('/wikiget/([^/]+)', pagehandlers.GetPage),
         ('/wikiview/([^/]+)', pagehandlers.View),
         ('/wikiedit/([^/]+)', pagehandlers.Edit),
         ('/wikisave/([^/]+)', pagehandlers.Save),
         ('/userlist', userhandlers.List),
         ('/userinfo/([^/]+)', userhandlers.Info),
         ('/useredit/([^/]+)', userhandlers.Edit),
         ('/usergetphoto/([^/]+)', userhandlers.GetPhoto),
         ('/mapview', maphandlers.View),
         ('/oldmapedit', maphandlers.OldEdit),
         ('/oldmapview', maphandlers.OldView),
         ('/oldmapkml', maphandlers.OldKMLOutput),
         ('/gen/request', Request ),
         ('/test', TestHandler),
         ('/.*', MainHandler),
         ]

def main():
    application = webapp.WSGIApplication(_URLS, debug=_DEBUG)
    wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
    main()
